package com.edol.painting.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.PorterDuff.Mode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.Shader.TileMode;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;

import com.doodle.common.utils.Utils;
import com.edol.painting.R;

public class CustomSeekBar extends View {

    private int num = 0;

    private static final String TAG = "CustomSeekBar";

    private int mBarW = 0;
    private int mBarH = 0;

    private int mProgressMax = 100;
    private int mCurrentProgress = 0;

    private int mResultColor = Color.TRANSPARENT;

    private Drawable mThumbDrawable;

    private RectF mDrawRectF = new RectF();
    private Rect mDrawRect = new Rect();

    private Paint mPaint;

    private Bitmap mBgBitmap;
    private Bitmap mAlphaBitmap;
    private Canvas mAlphaCanvas;
    private RectF mAlphaRectF;
    private Paint mAlphaPaint;

    private float mTouchSlope = 4;
    private boolean hasMeasure = false;
    private boolean mTouchMoved = false;
    private boolean mTouchClickable = true;

    private float mRoundAngle = getResources().getDimensionPixelSize(R.dimen.seekbar_round_angle);
    
    public CustomSeekBar(Context context) {
        super(context);
        Log.i(TAG, "CustomSeekBar()");
    }

    public CustomSeekBar(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs,defStyle);
        Log.i(TAG, "CustomSeekBar(X,X,X)");
    }

    public CustomSeekBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        num = getId();
        mTouchSlope = ViewConfiguration.get(context).getScaledTouchSlop();
        Log.i(TAG, "CustomSeekBar(X,X)-num="+num);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomSeekBar);
        Drawable bgDrawable = a.getDrawable(R.styleable.CustomSeekBar_layer0_bg);
        if (bgDrawable != null) {
            mBgBitmap = ((BitmapDrawable)bgDrawable).getBitmap();
            mBarW = mBgBitmap.getWidth();
        	mBarH = mBgBitmap.getHeight();
        }
        mResultColor = a.getColor(R.styleable.CustomSeekBar_layer1_color, Color.TRANSPARENT);
        mThumbDrawable = a.getDrawable(R.styleable.CustomSeekBar_layer3_thumb);
        mProgressMax = a.getInt(R.styleable.CustomSeekBar_progressMax, 100);
        a.recycle();

        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setStyle(Style.FILL);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width ,height;
        setMeasuredDimension(width = measureWidth(widthMeasureSpec), height = measureHeight(heightMeasureSpec));
        mDrawRect.set(getPaddingLeft(), getPaddingTop(), width - getPaddingRight(), height - getPaddingBottom());
        mDrawRectF.set(mDrawRect);
        if (mAlphaPaint != null) {
        	Shader shader = new LinearGradient(0, 0, mDrawRectF.width(), mDrawRectF.height(), Color.TRANSPARENT, mResultColor, TileMode.REPEAT);
        	mAlphaPaint.setShader(shader);
        	mAlphaRectF = new RectF(0, 0, mDrawRectF.width(), mDrawRectF.height());
        }
    }
    
    private int measureHeight(int heightMeasureSpec) {
        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
        if (heightSpecMode == MeasureSpec.EXACTLY) {
            return MeasureSpec.getSize(heightMeasureSpec);
        } else {
            return Math.min(getPaddingTop() + mBarH + getPaddingBottom(), MeasureSpec.getSize(heightMeasureSpec));
        }
    }

    private int measureWidth(int widthMeasureSpec) {
        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
        if (widthSpecMode == MeasureSpec.EXACTLY) {
            return MeasureSpec.getSize(widthMeasureSpec);
        } else {
            return Math.min(getPaddingLeft() + mBarW + getPaddingRight(), MeasureSpec.getSize(widthMeasureSpec));
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (!hasMeasure) {
            hasMeasure = true;

            mThumbOffset = (int)(mCurrentProgress * 1.0f / mProgressMax * (mDrawRect.width() - mDrawRect.height()));
            mCurrentOffset = mThumbOffset;
        }

        if (mBgBitmap != null) {
	        if (mAlphaPaint != null) {
	        	mAlphaCanvas.drawColor(0x0, Mode.CLEAR);
	        	mAlphaCanvas.drawBitmap(mBgBitmap, 0, 0, null);
		    	mAlphaCanvas.drawRoundRect(mAlphaRectF, mRoundAngle, mRoundAngle, mAlphaPaint);
	        	canvas.drawBitmap(mAlphaBitmap, null, mDrawRect, null);
	        } else {
	        	canvas.drawBitmap(mBgBitmap, null, mDrawRect, null);
	        }
        }

        // draw thumb 
        if (mThumbDrawable != null) {
            mThumbDrawable.setBounds(mDrawRect.left + mThumbOffset, mDrawRect.top, mDrawRect.left + mThumbOffset + mDrawRect.height(), mDrawRect.bottom);
            mThumbDrawable.draw(canvas);
        }
    }

    public void setCurrentColor(int color) {
    	if (mAlphaPaint == null) {
    		mAlphaPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    	}
    	if (mAlphaPaint != null) {
	        mResultColor = color;
	        mAlphaPaint.reset();
	    	Shader shader = new LinearGradient(0, 0, mDrawRectF.width(), mDrawRectF.height(), Color.TRANSPARENT, color, TileMode.REPEAT);
	    	mAlphaPaint.setShader(shader);
	    	if (mAlphaBitmap == null) {
	    		mAlphaBitmap = Bitmap.createBitmap(mBgBitmap.getWidth(), mBgBitmap.getHeight(), Config.ARGB_8888);
	    		mAlphaCanvas = new Canvas(mAlphaBitmap);
	    	}
	    	invalidate();
    	}
    }

    public void setProgress(int progress) {
        mCurrentProgress = Utils.clamp(progress, 0, mProgressMax);
        mThumbOffset = (mDrawRect.width() - mDrawRect.height()) * mCurrentProgress / mProgressMax;
        mCurrentOffset = mThumbOffset;
        invalidate();
    }

    public void setMax(int progressMax) {
        mProgressMax = progressMax;
    }

    public int getMax() {
        return mProgressMax;
    }

    public int getProgress() {
        return mCurrentProgress;
    }

    private int mThumbOffset = 0;
    private int mCurrentOffset = 0;
    private int mLastX;
    @Override
    public boolean onTouchEvent(MotionEvent event) {
    	if (mTouchClickable) {
	        int action = event.getAction();
	        int x = (int)event.getX();
	        switch(action) {
	            case MotionEvent.ACTION_DOWN:
	                mTouchMoved = false;
	                mLastX = x;
	                break;
	            case MotionEvent.ACTION_MOVE:
	                if (!mTouchMoved) {
	                    if (Math.abs(x - mLastX) >= mTouchSlope) {
	                        mTouchMoved = true;
	                    }
	                }
	                if (mTouchMoved) {
	                    int xDelta = x - mLastX;
	                    mCurrentOffset += xDelta;
	                    mCurrentOffset = Utils.clamp(mCurrentOffset, 0, mDrawRect.width() - mDrawRect.height());
	                    if (mThumbOffset != mCurrentOffset) {
	                        mThumbOffset = mCurrentOffset;
	                        mCurrentProgress = mProgressMax * mThumbOffset / (mDrawRect.width() - mDrawRect.height());
	                        if (mListener != null) {
	                            mListener.onProgressChanged(this, mCurrentProgress);
	                        }
	                        invalidate();
	                    }
	                    mLastX = x;
	                }
	                break;
	            case MotionEvent.ACTION_UP:
	                if (!mTouchMoved) {
	                    mCurrentOffset = x - mDrawRect.left;
	                    mCurrentOffset = Utils.clamp(mCurrentOffset, 0, mDrawRect.width() - mDrawRect.height());
	                    if (mThumbOffset != mCurrentOffset) {
	                        mThumbOffset = mCurrentOffset;
	                        mCurrentProgress = mProgressMax * mThumbOffset / (mDrawRect.width() - mDrawRect.height());
	                        mCurrentProgress = Utils.clamp(mCurrentProgress, 0, mProgressMax);
	                    }
	                    mLastX = mThumbOffset + mDrawRect.left;
	                }
	                if (mListener != null) {
	                    mListener.onProgressEnd(this, mCurrentProgress);
	                }
	                invalidate();
	                break;
	        }
    	}
        return true;
    }
    
    public void setOnTouchClickable(boolean b) {
    	mTouchClickable = b;
    }

    private OnProgressChangedListener mListener;

    public interface OnProgressChangedListener{
        void onProgressChanged(CustomSeekBar seekbar, int progress);
        void onProgressEnd(CustomSeekBar seekBar, int progress);
    }

    public void setProgressChangedListener(OnProgressChangedListener listener) {
        mListener = listener;
    }
    
    public void clear() {
    	mThumbDrawable.setCallback(null);
    	mThumbDrawable = null;
    	if (mAlphaBitmap != null) {
	    	mAlphaBitmap.recycle();
	    	mAlphaBitmap = null;
    	}
    }

}
